package com.xunmall.executors.client;

import com.xunmall.executors.framework.AbstractExecutorGroupFactory;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.Assert;

import java.io.*;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * @author wangyj03@zenmen.com
 * @description  * 基于本地配置文件，实现动态线程组的工厂类
 * 	              支持定时刷新指定的配置文件，动态更新线程组核心参数
 * @date 2020/9/28 19:03
 */
public class LocalConfigExecutorGroupFactory extends AbstractExecutorGroupFactory {

    private String localFile;

    private long modifiedTime = 0;

    private File localFileObject = null;

    private ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();

    public void setLocalFile(String localFile) {
        this.localFile = localFile;
    }

    @Override
    protected void init() throws Exception {
        Assert.isTrue(StringUtils.isNotEmpty(localFile));
        logger.info("========== localFile :" + localFile);
        if (localFile.startsWith("/") || localFile.contains(":" + File.separator)) {
            //文件是绝对路径
            localFileObject = new File(localFile);
        } else {
            String classResourceFilePath = getClass().getResource("/").getFile() + localFile;
            logger.info(String.format("======= classResourceFilePath [%s]", classResourceFilePath));
            localFileObject = new File(classResourceFilePath);
        }
        if (!localFileObject.exists()) {
            throw new FileNotFoundException("local file not found : " + localFileObject.getAbsolutePath());
        }
        modifiedTime = localFileObject.lastModified();
        readAndParse();

        //设置初始化标识
        this.inited = true;

        //定期检查配置文件是否发生变更，并刷新对应的线程池对象
        executorService.scheduleWithFixedDelay(new RefreshTask(), 10, 5, TimeUnit.SECONDS);
    }

    private void readAndParse() throws IOException {
        InputStream resourceAsStream = null;
        try {
            resourceAsStream = new FileInputStream(localFileObject);
            parseConfig(IOUtils.toString(resourceAsStream));
        } catch (Exception e) {
            logger.error("read and parse config exception", e);
        } finally {
            IOUtils.closeQuietly(resourceAsStream);
        }
    }

    class RefreshTask implements Runnable {
        @Override
        public void run() {
            long ts = localFileObject.lastModified();
            if (ts > modifiedTime) {
                try {
                    readAndParse();
                    modifiedTime = ts;
                    logger.info(String.format("local config file [%s] is modified, read and reload executors", localFile));
                } catch (IOException e) {
                    logger.error("read and parse config exception", e);
                }
            }
        }

    }
}
